home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1 / win / x11 / winx.c < prev   
Encoding:
C/C++ Source or Header  |  1993-01-25  |  44.2 KB  |  1,653 lines

  1. /*    SCCS Id: @(#)winX.c    3.1    93/01/22          */
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * "Main" file for the X window-port.  This contains most of the interface
  7.  * routines.  Please see doc/window.doc for an description of the window
  8.  * interface.
  9.  */
  10. #include <X11/Intrinsic.h>
  11. #include <X11/StringDefs.h>
  12. #include <X11/Shell.h>
  13. #include <X11/Xaw/AsciiText.h>
  14. #include <X11/Xaw/Label.h>
  15. #include <X11/Xaw/Form.h>
  16. #include <X11/Xaw/Cardinals.h>
  17. #include <X11/Xatom.h>
  18. #include <X11/Xos.h>
  19. /* for color support; should be ifdef TEXTCOLOR, but must come before hack.h */
  20. #include <X11/IntrinsicP.h>
  21.  
  22. #include "hack.h"
  23. #include "winX.h"
  24.  
  25. /* Should be defined in <X11/Intrinsic.h> but you never know */
  26. #ifndef XtSpecificationRelease
  27. #define XtSpecificationRelease 0
  28. #endif
  29.  
  30. /*
  31.  * Icons.
  32.  */
  33. #include "../win/X11/nh72icon"
  34. #include "../win/X11/nh56icon"
  35. #include "../win/X11/nh32icon"
  36.  
  37. static struct icon_info {
  38.     const char *name;
  39.     char *bits;
  40.     unsigned width, height;
  41. } icon_data[] = {
  42.     { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height },
  43.     { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height },
  44.     { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height },
  45.     { NULL, NULL, 0, 0 }
  46. };
  47.  
  48. /*
  49.  * Private global variables (shared among the window port files).
  50.  */
  51. struct xwindow window_list[MAX_WINDOWS];
  52. AppResources appResources;
  53. void (*input_func)();
  54. int click_x, click_y, click_button;    /* Click position on a map window   */
  55.                     /* (filled by set_button_values()). */
  56.  
  57.  
  58. /* Interface definition, for windows.c */
  59. struct window_procs X11_procs = {
  60.     "X11",
  61.     X11_init_nhwindows,
  62.     X11_player_selection,
  63.     X11_askname,
  64.     X11_get_nh_event,
  65.     X11_exit_nhwindows,
  66.     X11_suspend_nhwindows,
  67.     X11_resume_nhwindows,
  68.     X11_create_nhwindow,
  69.     X11_clear_nhwindow,
  70.     X11_display_nhwindow,
  71.     X11_destroy_nhwindow,
  72.     X11_curs,
  73.     X11_putstr,
  74.     X11_display_file,
  75.     X11_start_menu,
  76.     X11_add_menu,
  77.     X11_end_menu,
  78.     X11_select_menu,
  79.     X11_update_inventory,
  80.     X11_mark_synch,
  81.     X11_wait_synch,
  82. #ifdef CLIPPING
  83.     X11_cliparound,
  84. #endif
  85.     X11_print_glyph,
  86.     X11_raw_print,
  87.     X11_raw_print_bold,
  88.     X11_nhgetch,
  89.     X11_nh_poskey,
  90.     X11_nhbell,
  91.     X11_doprev_message,
  92.     X11_yn_function,
  93.     X11_getlin,
  94. #ifdef COM_COMPL
  95.     X11_get_ext_cmd,
  96. #endif /* COM_COMPL */
  97.     X11_number_pad,
  98.     X11_delay_output,
  99.     /* other defs that really should go away (they're tty specific) */
  100.     X11_start_screen,
  101.     X11_end_screen,
  102. };
  103.  
  104. /*
  105.  * Local functions.
  106.  */
  107. static void FDECL(dismiss_file, (Widget, XEvent*, String*, Cardinal*));
  108. static void FDECL(yn_key, (Widget, XEvent*, String*, Cardinal*));
  109. static int FDECL(input_event, (int));
  110. static void NDECL(init_standard_windows);
  111.  
  112.  
  113. /*
  114.  * Local variables.
  115.  */
  116. static boolean x_inited = FALSE;    /* TRUE if window system is set up. */
  117. static winid message_win = WIN_ERR,    /* These are the winids of the        */
  118.          map_win     = WIN_ERR,    /*   message, map, and status        */
  119.          status_win  = WIN_ERR;    /*   windows, when they are created */
  120.                     /*   in init_windows().            */
  121. static Pixmap icon_pixmap = None;    /* Pixmap for icon.            */
  122.  
  123. /*
  124.  * Find the window structure that corresponds to the given widget.  Note
  125.  * that this is not the popup widget, nor the viewport, but the child.
  126.  */
  127. struct xwindow *
  128. find_widget(w)
  129.     Widget w;
  130. {
  131.     int windex;
  132.     struct xwindow *wp;
  133.  
  134.     /* This is sad.  Search to find the corresponding window. */
  135.     for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++)
  136.     if (wp->type != NHW_NONE && wp->w == w) break;
  137.     if (windex == MAX_WINDOWS) panic("find_widget:  can't match widget");
  138.     return wp;
  139. }
  140.  
  141. /*
  142.  * Find a free window slot for use.
  143.  */
  144. static winid
  145. find_free_window()
  146. {
  147.     int windex;
  148.     struct xwindow *wp;
  149.  
  150.     for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS; windex++, wp++)
  151.     if (wp->type == NHW_NONE) break;
  152.  
  153.     if (windex == MAX_WINDOWS)
  154.     panic("find_free_window: no free windows!");
  155.     return (winid) windex;
  156. }
  157.  
  158. #ifdef TEXTCOLOR
  159. /*
  160.  * Color conversion.  The default X11 color converters don't try very
  161.  * hard to find matching colors in PseudoColor visuals.  If they can't
  162.  * allocate the exact color, they puke and give you something stupid.
  163.  * This is an attempt to find some close readonly cell and use it.
  164.  */
  165. XtConvertArgRec const nhcolorConvertArgs[] = {
  166.     {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.screen),
  167.      sizeof(Screen *)},
  168.     {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.colormap),
  169.      sizeof(Colormap)}
  170. };
  171.  
  172. #define done(type, value) \
  173.     {                            \
  174.         if (toVal->addr != NULL) {                \
  175.         if (toVal->size < sizeof(type)) {        \
  176.             toVal->size = sizeof(type);            \
  177.             return False;                \
  178.         }                        \
  179.         *(type*)(toVal->addr) = (value);        \
  180.         }                            \
  181.         else {                        \
  182.         static type static_val;                \
  183.         static_val = (value);                \
  184.         toVal->addr = (genericptr_t)&static_val;    \
  185.         }                            \
  186.         toVal->size = sizeof(type);                \
  187.         return True;                    \
  188.     }
  189.  
  190. /* decl.h declares these, but it screws up structure references -dlc */
  191. #undef red
  192. #undef green
  193. #undef blue
  194.  
  195. /* Return True if something close was found. */
  196. Boolean
  197. nhCloseColor(screen, colormap, str, color)
  198. Screen     *screen;    /* screen to use */
  199. Colormap colormap;    /* the colormap to use */
  200. char     *str;        /* color name */
  201. XColor   *color;    /* the X color structure; changed only if successful */
  202. {
  203.     int        ncells;
  204.     long    cdiff = 16777216; /* 2^24; hopefully our map is smaller */
  205.     XColor    tmp;
  206.     static    XColor *table = 0;
  207.     register    i, j;
  208.     register long tdiff;
  209.  
  210.     /* if the screen doesn't have a big colormap, don't waste our time */
  211.     /* or if it's huge, and _some_ match should have been possible */
  212.     if((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096)
  213.     return False;
  214.  
  215.     if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp))
  216.     return False;
  217.  
  218.     if (!table) {
  219.     table = (XColor *) XtCalloc(ncells, sizeof(XColor));
  220.     for(i=0; i<ncells; i++)
  221.         table[i].pixel = i;
  222.     XQueryColors(DisplayOfScreen(screen), colormap, table, ncells);
  223.     }
  224.  
  225.     /* go thru cells and look for the one with smallest diff */
  226.     /* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */
  227.     /* a more knowledgeable color person might improve this -dlc */
  228.     for(i=0; i<ncells; i++) {
  229.     if(table[i].flags == tmp.flags) {
  230.         j = (int)table[i].red - (int)tmp.red;
  231.         if(j < 0) j = -j;
  232.         tdiff = j;
  233.         j = (int)table[i].green - (int)tmp.green;
  234.         if(j < 0) j = -j;
  235.         tdiff += j;
  236.         j = (int)table[i].blue - (int)tmp.blue;
  237.         if(j < 0) j = -j;
  238.         tdiff += j;
  239.         if(tdiff < cdiff) {
  240.         cdiff = tdiff;
  241.         tmp.pixel = i; /* table[i].pixel == i */
  242.         }
  243.     }
  244.     }
  245.  
  246.     if(cdiff == 16777216) return False;    /* nothing found?! */
  247.  
  248.     /*
  249.      * Found something.  Return it and mark this color as used to avoid
  250.      * reuse.  Reuse causes major contrast problems :-)
  251.      */
  252.     color->pixel = tmp.pixel;
  253.     table[tmp.pixel].flags = 0;
  254.     return True;
  255. }
  256.  
  257. Boolean
  258. nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
  259. Display*    dpy;
  260. XrmValuePtr    args;
  261. Cardinal    *num_args;
  262. XrmValuePtr    fromVal;
  263. XrmValuePtr    toVal;
  264. XtPointer    *closure_ret;
  265. {
  266.     String        str = (String)fromVal->addr;
  267.     XColor        screenColor;
  268.     XColor        exactColor;
  269.     Screen        *screen;
  270.     XtAppContext    app = XtDisplayToApplicationContext(dpy);
  271.     Colormap        colormap;
  272.     Status        status;
  273.     String          params[1];
  274.     Cardinal        num_params=1;
  275.  
  276.     if (*num_args != 2) {
  277.      XtAppWarningMsg(app, "wrongParameters", "cvtStringToPixel",
  278.     "XtToolkitError",
  279.     "String to pixel conversion needs screen and colormap arguments",
  280.         (String *)NULL, (Cardinal *)NULL);
  281.      return False;
  282.     }
  283.  
  284.     screen = *((Screen **) args[0].addr);
  285.     colormap = *((Colormap *) args[1].addr);
  286.  
  287.     /* If Xt colors, use the Xt routine and hope for the best */
  288. #if (XtSpecificationRelease >= 5)
  289.     if ((strcmpi(str, XtDefaultBackground) == 0) ||
  290.     (strcmpi(str, XtDefaultForeground) == 0)) {
  291.     return
  292.       XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret);
  293.     }
  294. #else
  295.     if (strcmpi(str, XtDefaultBackground) == 0) {
  296.     *closure_ret = (char*)False;
  297.     done(Pixel, WhitePixelOfScreen(screen));
  298.     }
  299.     if (strcmpi(str, XtDefaultForeground) == 0) {
  300.     *closure_ret = (char*)False;
  301.     done(Pixel, BlackPixelOfScreen(screen));
  302.     }
  303. #endif
  304.  
  305.     status = XAllocNamedColor(DisplayOfScreen(screen), colormap,
  306.                   (char*)str, &screenColor, &exactColor);
  307.     if (status == 0) {
  308.     String msg, type;
  309.     params[0] = str;
  310.     /* Server returns a specific error code but Xlib discards it.  Ugh */
  311.     if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str,
  312.              &exactColor, &screenColor)) {
  313.         /* try to find another color that will do */
  314.         if (nhCloseColor(screen, colormap, (char*) str, &screenColor)) {
  315.         *closure_ret = (char*)True;
  316.         done(Pixel, screenColor.pixel);
  317.         }
  318.         type = "noColormap";
  319.         msg = "Cannot allocate colormap entry for \"%s\"";
  320.     }
  321.     else {
  322.         type = "badValue";
  323.         msg = "Color name \"%s\" is not defined";
  324.     }
  325.  
  326.     XtAppWarningMsg(app, type, "cvtStringToPixel",
  327.             "XtToolkitError", msg, params, &num_params);
  328.     *closure_ret = False;
  329.     return False;
  330.     } else {
  331.     *closure_ret = (char*)True;
  332.         done(Pixel, screenColor.pixel);
  333.     }
  334. }
  335.  
  336. /* ARGSUSED */
  337. static void
  338. nhFreePixel(app, toVal, closure, args, num_args)
  339. XtAppContext    app;
  340. XrmValuePtr    toVal;
  341. XtPointer    closure;
  342. XrmValuePtr    args;
  343. Cardinal    *num_args;
  344. {
  345.     Screen        *screen;
  346.     Colormap        colormap;
  347.  
  348.     if (*num_args != 2) {
  349.      XtAppWarningMsg(app, "wrongParameters",
  350.              "freePixel", "XtToolkitError",
  351.              "Freeing a pixel requires screen and colormap arguments",
  352.              (String *)NULL, (Cardinal *)NULL);
  353.      return;
  354.     }
  355.  
  356.     screen = *((Screen **) args[0].addr);
  357.     colormap = *((Colormap *) args[1].addr);
  358.  
  359.     if (closure) {
  360.     XFreeColors( DisplayOfScreen(screen), colormap,
  361.              (unsigned long*)toVal->addr, 1, (unsigned long)0
  362.             );
  363.     }
  364. }
  365. #endif /* TEXTCOLOR */
  366.  
  367. /* Global Functions ======================================================== */
  368. void
  369. X11_raw_print(str)
  370.     const char *str;
  371. {
  372.     (void) puts(str);
  373. }
  374.  
  375. void
  376. X11_raw_print_bold(str)
  377.     const char *str;
  378. {
  379.     (void) puts(str);
  380. }
  381.  
  382. void
  383. X11_curs(window, x, y)
  384.     winid window;
  385.     int x, y;
  386. {
  387.     check_winid(window);
  388.  
  389.     if (x < 0 || x >= COLNO) {
  390.     impossible("curs:  bad x value [%d]", x);
  391.     x = 0;
  392.     }
  393.     if (y < 0 || y >= ROWNO) {
  394.     impossible("curs:  bad y value [%d]", y);
  395.     y = 0;
  396.     }
  397.  
  398.     window_list[window].cursx = x;
  399.     window_list[window].cursy = y;
  400. }
  401.  
  402. void
  403. X11_putstr(window, attr, str)
  404.     winid window;
  405.     int attr;
  406.     const char *str;
  407. {
  408.     winid new_win;
  409.     struct xwindow *wp;
  410.  
  411.     check_winid(window);
  412.     wp = &window_list[window];
  413.  
  414.     switch (wp->type) {
  415.     case NHW_MESSAGE:
  416.         Strcpy(toplines, str);    /* for Norep(). */
  417.         append_message(wp, str);
  418.         break;
  419.     case NHW_STATUS:
  420.         adjust_status(wp, str);
  421.         break;
  422.     case NHW_MAP:
  423.         impossible("putstr: called on map window \"%s\"", str);
  424.         break;
  425.     case NHW_MENU:
  426.         if (wp->menu_information->is_menu) {
  427.         impossible(
  428.             "putstr:  called on a menu window, \"%s\" discarded",
  429.             str);
  430.         break;
  431.         }
  432.         /*
  433.          * Change this menu window into a text window by creating a
  434.          * new text window, then copying it to this winid.
  435.          */
  436.         new_win = X11_create_nhwindow(NHW_TEXT);
  437.         X11_destroy_nhwindow(window);
  438.         *wp = window_list[new_win];
  439.         window_list[new_win].type = NHW_NONE;    /* allow re-use */
  440.         /* fall though to add text */
  441.     case NHW_TEXT:
  442.         add_to_text_window(wp, attr, str);
  443.         break;
  444.     default:
  445.         impossible("putstr: unknown window type [%d] \"%s\"",
  446.                                 wp->type, str);
  447.     }
  448. }
  449.  
  450. /* We do event processing as a callback, so this is a null routine. */
  451. void X11_get_nh_event() { return; }
  452.  
  453. int
  454. X11_nhgetch()
  455. {
  456.     return input_event(EXIT_ON_KEY_PRESS);
  457. }
  458.  
  459.  
  460. int
  461. X11_nh_poskey(x, y, mod)
  462.     int *x, *y, *mod;
  463. {
  464.     int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
  465.  
  466.     if (val == 0) {    /* user clicked on a map window */
  467.     *x   = click_x;
  468.     *y   = click_y;
  469.     *mod = click_button;
  470.     }
  471.     return val;
  472. }
  473.  
  474.  
  475. winid
  476. X11_create_nhwindow(type)
  477.     int type;
  478. {
  479.     winid window;
  480.     struct xwindow *wp;
  481.  
  482.     if (!x_inited)
  483.     panic("create_nhwindow:  windows not initialized");
  484.  
  485.     /*
  486.      * We have already created the standard message, map, and status
  487.      * windows in the window init routine.  The first window of that
  488.      * type to be created becomes the standard.
  489.      *
  490.      * A better way to do this would be to say that init_nhwindows()
  491.      * has already defined these three windows.
  492.      */
  493.     if (type == NHW_MAP && map_win != WIN_ERR) {
  494.     window = map_win;
  495.     map_win = WIN_ERR;
  496.     return window;
  497.     }
  498.     if (type == NHW_MESSAGE && message_win != WIN_ERR) {
  499.     window = message_win;
  500.     message_win = WIN_ERR;
  501.     return window;
  502.     }
  503.     if (type == NHW_STATUS && status_win != WIN_ERR) {
  504.     window = status_win;
  505.     status_win = WIN_ERR;
  506.     return window;
  507.     }
  508.  
  509.     window = find_free_window();
  510.     wp = &window_list[window];
  511.  
  512.     /* The create routines will set type, popup, w, and Win_info. */
  513.     wp->prevx = wp->prevy = wp->cursx = wp->cursy =
  514.                 wp->pixel_width = wp->pixel_height = 0;
  515.  
  516.     switch (type) {
  517.     case NHW_MAP:
  518.         create_map_window(wp, TRUE, (Widget) 0);
  519.         break;
  520.     case NHW_MESSAGE:
  521.         create_message_window(wp, TRUE, (Widget) 0);
  522.         break;
  523.     case NHW_STATUS:
  524.         create_status_window(wp, TRUE, (Widget) 0);
  525.         break;
  526.     case NHW_MENU:
  527.         create_menu_window(wp);
  528.         break;
  529.     case NHW_TEXT:
  530.         create_text_window(wp);
  531.         break;
  532.     default:
  533.         panic("create_nhwindow: unknown type [%d]\n", type);
  534.         break;
  535.     }
  536.     return window;
  537. }
  538.  
  539. void
  540. X11_clear_nhwindow(window)
  541.     winid window;
  542. {
  543.     struct xwindow *wp;
  544.  
  545.     check_winid(window);
  546.     wp = &window_list[window];
  547.  
  548.     switch (wp->type) {
  549.     case NHW_MAP:
  550.         clear_map_window(wp);
  551.         break;
  552.     case NHW_STATUS:
  553.     case NHW_TEXT:
  554.     case NHW_MENU:
  555.     case NHW_MESSAGE:
  556.         /* do nothing for these window types */
  557.         break;
  558.     default:
  559.         panic("clear_nhwindow: unknown window type [%d]\n", wp->type);
  560.         break;
  561.     }
  562. }
  563.  
  564. void
  565. X11_display_nhwindow(window, blocking)
  566.     winid window;
  567.     boolean blocking;
  568. {
  569.     struct xwindow *wp;
  570.     check_winid(window);
  571.  
  572.     wp = &window_list[window];
  573.  
  574.     switch (wp->type) {
  575.     case NHW_MAP:
  576.         if (wp->popup)
  577.         nh_XtPopup(wp->popup, XtGrabNone, wp->w);
  578.         /*else
  579.          *  XtMapWidget(toplevel);
  580.          *
  581.          * We don't need to do the above because we never have
  582.          * MappedWhenManaged unset because the DEC server doesn't
  583.          * like it.  See comment above XtSetMappedWhenManaged() in
  584.          * init_standard_windows().
  585.          */
  586.         display_map_window(wp);    /* flush map */
  587.  
  588.         /*
  589.          * We need to flush the message window here due to the way the tty
  590.          * port is set up.  To flush a window, you need to call this
  591.          * routine.  However, the tty port _pauses_ with a --more-- if we
  592.          * do a display_nhwindow(WIN_MESSAGE, FALSE).  Thus, we can't call
  593.          * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
  594.          * get a --more-- after every line.
  595.          *
  596.          * Perhaps the window document should mention that when the map
  597.          * is flushed, everything on the three main windows should be
  598.          * flushed.  Note: we don't need to flush the status window
  599.          * because we don't buffer changes.
  600.          */
  601.         if (WIN_MESSAGE != WIN_ERR)
  602.         display_message_window(&window_list[WIN_MESSAGE]);
  603.         if (blocking)
  604.         (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
  605.         break;
  606.     case NHW_MESSAGE:
  607.         if (wp->popup)
  608.          nh_XtPopup(wp->popup, XtGrabNone, wp->w);
  609.         /*else
  610.          *    XtMapWidget(toplevel);
  611.          *
  612.          * See comment in NHW_MAP case.
  613.          */
  614.  
  615.         display_message_window(wp);    /* flush messages */
  616.         break;
  617.     case NHW_STATUS:
  618.         if (wp->popup)
  619.         nh_XtPopup(wp->popup, XtGrabNone, wp->w);
  620.         /*else
  621.          *    XtMapWidget(toplevel);
  622.          *
  623.          * See comment in NHW_MAP case.
  624.          */
  625.  
  626.         break;            /* no flushing necessary */
  627.     case NHW_MENU:
  628.         (void) X11_select_menu(window); /* pop up menu (global routine) */
  629.         break;
  630.     case NHW_TEXT:
  631.         display_text_window(wp, blocking);    /* pop up text window */
  632.         break;
  633.     default:
  634.         panic("display_nhwindow: unknown window type [%d]\n", wp->type);
  635.         break;
  636.     }
  637. }
  638.  
  639. void
  640. X11_destroy_nhwindow(window)
  641.     winid window;
  642. {
  643.     struct xwindow *wp;
  644.     check_winid(window);
  645.  
  646.     /*
  647.      * "Zap" known windows, but don't destroy them.  We need to keep the
  648.      * toplevel widget popped up so that later windows (e.g. tombstone)
  649.      * are visible on DECWindow systems.  This is due to the virtual
  650.      * roots that the DECWindow wm creates.
  651.      */
  652.     if (window == WIN_MESSAGE) {
  653.     WIN_MESSAGE = WIN_ERR;
  654.     flags.window_inited = 0;
  655.     return;
  656.     } else if (window == WIN_MAP) {
  657.     WIN_MAP = WIN_ERR;
  658.     return;
  659.     } else if (window == WIN_STATUS) {
  660.     WIN_STATUS = WIN_ERR;
  661.     return;
  662.     } else if (window == WIN_INVEN) {
  663.     WIN_INVEN = WIN_ERR;
  664.     return;
  665.     }
  666.  
  667.     wp = &window_list[window];
  668.  
  669.     switch (wp->type) {
  670.     case NHW_MAP:
  671.         destroy_map_window(wp);
  672.         break;
  673.     case NHW_MENU:
  674.         destroy_menu_window(wp);
  675.         break;
  676.     case NHW_TEXT:
  677.         destroy_text_window(wp);
  678.         break;
  679.     case NHW_STATUS:
  680.         destroy_status_window(wp);
  681.         break;
  682.     case NHW_MESSAGE:
  683.         destroy_message_window(wp);
  684.         break;
  685.     default:
  686.         panic("destroy_nhwindow: unknown window type [%d]", wp->type);
  687.         break;
  688.     }
  689. }
  690.  
  691. /* We don't implement a continous invent screen, so this is null. */
  692. void X11_update_inventory() { return; }
  693.  
  694. /* The current implementation has all of the saved lines on the screen. */
  695. int X11_doprev_message() { return 0; }
  696.  
  697. void
  698. X11_nhbell()
  699. {
  700.     /* We can't use XBell until toplevel has been initialized. */
  701.     if (x_inited)
  702.     XBell(XtDisplay(toplevel), 0);
  703.     /* else print ^G ?? */
  704. }
  705.  
  706. void X11_mark_synch()
  707. {
  708.     if (x_inited) {
  709.     /*
  710.      * the window document is a bit unclear about the status of text
  711.      * that has been pline()d but not displayed w/display_nhwindow(),
  712.      * though the main code and tty code assume that a pline() followed
  713.      * by mark_synch() results in the text being seen, even if
  714.      * display_nhwindow() wasn't called.  Duplicate this behavior.
  715.      */
  716.     if (WIN_MESSAGE != WIN_ERR)
  717.         display_message_window(&window_list[WIN_MESSAGE]);
  718.     XSync(XtDisplay(toplevel), False);
  719.     }
  720. }
  721.  
  722. void X11_wait_synch() {if (x_inited) XFlush(XtDisplay(toplevel)); }
  723.  
  724.  
  725. /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */
  726. void X11_resume_nhwindows() { return; }
  727.  
  728. /* ARGSUSED */
  729. void X11_suspend_nhwindows(str) const char *str; { return; }
  730.  
  731. /* Under X, we don't need to initialize the number pad. */
  732. /* ARGSUSED */
  733. void X11_number_pad(state) int state; { return; } /* called from options.c */
  734.  
  735.  
  736. void X11_start_screen() { return; } /* called from setftty() in unixtty.c */
  737. void X11_end_screen() { return; }   /* called from settty() in unixtty.c */
  738.  
  739.  
  740. /* init and exit nhwindows ------------------------------------------------- */
  741.  
  742. XtAppContext app_context;        /* context of application */
  743. Widget         toplevel = (Widget) 0;    /* toplevel widget */
  744.  
  745. static XtActionsRec actions[] = {
  746.     {"dismiss_file",    dismiss_file},    /* action for file viewing widget */
  747.     {"dismiss_text",    dismiss_text},    /* button action for text widget */
  748.     {"key_dismiss_text",key_dismiss_text},/* key action for text widget */
  749.     {"menu_key",    menu_key},    /* action for menu accelerators */
  750.     {"yn_key",        yn_key},    /* action for yn accelerators */
  751.     {"ec_key",        ec_key},    /* action for extended commands */
  752.     {"ps_key",        ps_key},    /* action for player selection */
  753. };
  754.  
  755. static XtResource resources[] = {
  756.     { "slow", "Slow", XtRBoolean, sizeof(Boolean),
  757.       XtOffset(AppResources *,slow), XtRString, "False" },
  758.     { "autofocus", "AutoFocus", XtRBoolean, sizeof(Boolean),
  759.       XtOffset(AppResources *,autofocus), XtRString, "False" },
  760.     { "message_line", "Message_line", XtRBoolean, sizeof(Boolean),
  761.       XtOffset(AppResources *,message_line), XtRString, "False" },
  762.     { "icon", "Icon", XtRString, sizeof(String),
  763.       XtOffset(AppResources *,icon), XtRString, "nh72" },
  764. };
  765.  
  766. void
  767. X11_init_nhwindows()
  768. {
  769.     static const char *banner_text[] = {
  770.     "NetHack",
  771.     "Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993",
  772.     "by Stichting Mathematisch Centrum and M. Stephenson.",
  773.     "See license for details.",
  774.     "",
  775.     "",
  776.     0
  777.     };
  778.     static const char *av[] = { "nethack" };
  779.     register const char **pp;
  780.     int i;
  781.     Cardinal num_args;
  782.     Arg args[4];
  783.  
  784.     /* Init windows to nothing. */
  785.     for (i = 0; i < MAX_WINDOWS; i++)
  786.     window_list[i].type = NHW_NONE;
  787.  
  788.     XSetIOErrorHandler((XIOErrorHandler) hangup);
  789.  
  790.     i = 1;
  791.     num_args = 0;
  792.     XtSetArg(args[num_args], XtNallowShellResize, True);    num_args++;
  793.     toplevel = XtAppInitialize(
  794.             &app_context,
  795.             "NetHack",        /* application class */
  796.             NULL, 0,        /* options list */
  797.             &i, av,        /* command line args */
  798.             NULL,        /* fallback resources */
  799.             args, num_args);
  800.  
  801.     /* We don't need to realize the top level widget. */
  802.  
  803. #ifdef TEXTCOLOR
  804.     /* add new color converter to deal with overused colormaps */
  805.     XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel,
  806.                nhcolorConvertArgs, XtNumber(nhcolorConvertArgs),
  807.                XtCacheByDisplay, nhFreePixel);
  808. #endif /* TEXTCOLOR */
  809.  
  810.     /* Register the actions mentioned in "actions". */
  811.     XtAppAddActions(app_context, actions, XtNumber(actions));
  812.  
  813.     /* Get application-wide resources */
  814.     XtGetApplicationResources(toplevel,(XtPointer)&appResources,
  815.                   resources,XtNumber(resources),NULL,ZERO);
  816.  
  817.     /* Initialize other things. */
  818.     init_standard_windows();
  819.     init_extended_commands_popup();
  820.  
  821.     /* Give the window manager an icon to use;  toplevel must be realized. */
  822.     if (appResources.icon && *appResources.icon) {
  823.     struct icon_info *ip;
  824.  
  825.     for (ip = icon_data; ip->name; ip++)
  826.         if (!strcmp(appResources.icon, ip->name)) {
  827.         icon_pixmap = XCreateBitmapFromData(XtDisplay(toplevel),
  828.                     XtWindow(toplevel),
  829.                     ip->bits, ip->width, ip->height);
  830.         if (icon_pixmap != None) {
  831.             XWMHints hints;
  832.  
  833.             hints.flags = IconPixmapHint;
  834.             hints.icon_pixmap = icon_pixmap;
  835.             XSetWMHints(XtDisplay(toplevel),
  836.                 XtWindow(toplevel), &hints);
  837.         }
  838.         break;
  839.         }
  840.     }
  841.  
  842.     x_inited = TRUE;    /* X is now initialized */
  843.  
  844.     /* Display the startup banner in the message window. */
  845.     for (pp = banner_text; *pp; pp++)
  846.     X11_putstr(WIN_MESSAGE, 0, *pp);
  847. }
  848.  
  849. /*
  850.  * Let the OS take care of almost everything.  This includes the "main"
  851.  * three windows:  message, map, and status.  Note that if I destroy one of
  852.  * the three main windows, they all will be destroyed, due to their shared
  853.  * parent.  I currently don't check such a thing occuring, so the whole mess
  854.  * will probably crash&burn if I tried it.
  855.  */
  856. /* ARGSUSED */
  857. void X11_exit_nhwindows(dummy)
  858.     const char *dummy;
  859. {
  860.     /* explicitly free the icon pixmap */
  861.     if (icon_pixmap != None) {
  862.     XFreePixmap(XtDisplay(toplevel), icon_pixmap);
  863.     icon_pixmap = None;
  864.     }
  865. }
  866.  
  867.  
  868. /* delay_output ------------------------------------------------------------ */
  869.  
  870. /*
  871.  * Timeout callback for delay_output().  Send a fake message to the map
  872.  * window.
  873.  */
  874. /* ARGSUSED */
  875. static void
  876. d_timeout(client_data, id)
  877.     XtPointer client_data;
  878.     XtIntervalId *id;
  879. {
  880.     XEvent event;
  881.     XClientMessageEvent *mesg;
  882.  
  883.     /* Set up a fake message to the event handler. */
  884.     mesg = (XClientMessageEvent *) &event;
  885.     mesg->type = ClientMessage;
  886.     mesg->message_type = XA_STRING;
  887.     mesg->format = 8;
  888.     XSendEvent(XtDisplay(window_list[WIN_MAP].w),
  889.         XtWindow(window_list[WIN_MAP].w),
  890.         False,
  891.         NoEventMask,
  892.         (XEvent*) mesg);
  893. }
  894.  
  895. /*
  896.  * Delay for 50ms.  This is not implemented asynch.  Maybe later.
  897.  * Start the timeout, then wait in the event loop.  The timeout
  898.  * function will send an event to the map window which will be waiting
  899.  * for a sent event.
  900.  */
  901. void
  902. X11_delay_output()
  903. {
  904.     if (!x_inited) return;
  905.  
  906.     (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0);
  907.  
  908.     /* The timeout function will enable the event loop exit. */
  909.     (void) x_event(EXIT_ON_SENT_EVENT);
  910. }
  911.  
  912.  
  913. /* askname ----------------------------------------------------------------- */
  914. /* Callback for askname dialog widget. */
  915. /* ARGSUSED */
  916. static void
  917. askname_done(w, client_data, call_data)
  918.     Widget w;
  919.     XtPointer client_data;
  920.     XtPointer call_data;
  921. {
  922.     int len;
  923.     char *s;
  924.     Widget dialog = (Widget) client_data;
  925.  
  926.     s = (char *) GetDialogResponse(dialog);
  927.  
  928.     len = strlen(s);
  929.     if (len == 0) {
  930.     X11_nhbell();
  931.     return;
  932.     }
  933.  
  934.     /* Truncate name if necessary */
  935.     if (len >= sizeof(plname)-1)
  936.     len = sizeof(plname)-1;
  937.  
  938.     (void) strncpy(plname, s, len);
  939.     plname[len] = '\0';
  940.  
  941.     nh_XtPopdown(XtParent(dialog));
  942.     exit_x_event = TRUE;
  943. }
  944.  
  945. void
  946. X11_askname()
  947. {
  948.     Widget popup, dialog;
  949.     Arg args[1];
  950.  
  951.     XtSetArg(args[0], XtNallowShellResize, True);
  952.  
  953.     popup = XtCreatePopupShell("askname", transientShellWidgetClass,
  954.                    toplevel, args, ONE);
  955.  
  956.     dialog = CreateDialog(popup, "dialog",
  957.                     askname_done, (XtCallbackProc) 0);
  958.  
  959.     SetDialogPrompt(dialog, "What is your name?");    /* set prompt */
  960.     SetDialogResponse(dialog, "");        /* set default answer */
  961.  
  962.     XtRealizeWidget(popup);
  963.     positionpopup(popup);        /* center on cursor */
  964.  
  965.     nh_XtPopup(popup, XtGrabExclusive, dialog);
  966.  
  967.     /* The callback will enable the event loop exit. */
  968.     (void) x_event(EXIT_ON_EXIT);
  969. }
  970.  
  971.  
  972. /* getline ----------------------------------------------------------------- */
  973. /* This uses Tim Theisen's dialog widget set (from GhostView). */
  974.  
  975. static Widget getline_popup, getline_dialog;
  976.  
  977. #define CANCEL_STR "\033"
  978. static char *getline_input;
  979.  
  980.  
  981. /* Callback for getline dialog widget. */
  982. /* ARGSUSED */
  983. static void
  984. done_button(w, client_data, call_data)
  985.     Widget w;
  986.     XtPointer client_data;
  987.     XtPointer call_data;
  988. {
  989.     char *s;
  990.     Widget dialog = (Widget) client_data;
  991.  
  992.     s = (char *) GetDialogResponse(dialog);
  993.  
  994.     if (strlen(s) == 0)
  995.     Strcpy(getline_input, CANCEL_STR);
  996.     else
  997.     Strcpy(getline_input, s);
  998.  
  999.     nh_XtPopdown(XtParent(dialog));
  1000.     exit_x_event = TRUE;
  1001. }
  1002.  
  1003. /* Callback for getline dialog widget. */
  1004. /* ARGSUSED */
  1005. static void
  1006. abort_button(w, client_data, call_data)
  1007.     Widget w;
  1008.     XtPointer client_data;
  1009.     XtPointer call_data;
  1010. {
  1011.     Widget dialog = (Widget) client_data;
  1012.  
  1013.     Strcpy(getline_input, CANCEL_STR);
  1014.     nh_XtPopdown(XtParent(dialog));
  1015.     exit_x_event = TRUE;
  1016. }
  1017.  
  1018.  
  1019. void
  1020. X11_getlin(question, input)
  1021.     const char *question;
  1022.     char *input;
  1023. {
  1024.     static boolean need_to_init = True;
  1025.  
  1026.     getline_input = input;
  1027.  
  1028.     flush_screen(1);
  1029.     if (need_to_init) {
  1030.     Arg args[1];
  1031.  
  1032.     need_to_init = False;
  1033.  
  1034.     XtSetArg(args[0], XtNallowShellResize, True);
  1035.  
  1036.     getline_popup = XtCreatePopupShell("getline",transientShellWidgetClass,
  1037.                    toplevel, args, ONE);
  1038.  
  1039.     getline_dialog = CreateDialog(getline_popup, "dialog",
  1040.                     done_button, abort_button);
  1041.  
  1042.     XtRealizeWidget(getline_popup);
  1043.     }
  1044.     SetDialogPrompt(getline_dialog, question);    /* set prompt */
  1045.     SetDialogResponse(getline_dialog, "");    /* set default answer */
  1046.     positionpopup(getline_popup);        /* center on cursor */
  1047.  
  1048.     nh_XtPopup(getline_popup, XtGrabNone, getline_dialog);
  1049.  
  1050.     /* The callback will enable the event loop exit. */
  1051.     (void) x_event(EXIT_ON_EXIT);
  1052. }
  1053.  
  1054.  
  1055. /* Display file ------------------------------------------------------------ */
  1056. static const char display_translations[] =
  1057.     "#override\n\
  1058.      <BtnDown>: dismiss_file()";
  1059.  
  1060.  
  1061. /* Callback for file dismissal. */
  1062. /*ARGSUSED*/
  1063. static void
  1064. dismiss_file(w, event, params, num_params)
  1065.     Widget w;
  1066.     XEvent *event;
  1067.     String *params;
  1068.     Cardinal *num_params;
  1069. {
  1070.     Widget popup = XtParent(w);
  1071.     nh_XtPopdown(popup);
  1072.     XtDestroyWidget(popup);
  1073. }
  1074.  
  1075. void
  1076. X11_display_file(str, complain)
  1077.     const char *str;
  1078.     boolean complain;
  1079. {
  1080.     FILE *fp;
  1081.     Arg args[12];
  1082.     Cardinal num_args;
  1083.     Widget popup, dispfile;
  1084.     Position top_margin, bottom_margin, left_margin, right_margin;
  1085.     XFontStruct *fs;
  1086.     int new_width, new_height;
  1087. #define LLEN 128
  1088.     char line[LLEN];
  1089.     int num_lines;
  1090.  
  1091.     /* Use the port-independent file opener to see if the file exists. */
  1092.     fp = fopen_datafile(str, "r");
  1093.  
  1094.     if (!fp) {
  1095.     if(complain) pline("Cannot open %s.  Sorry.", str);
  1096.  
  1097.     return;    /* it doesn't exist, ignore */
  1098.     }
  1099.  
  1100.     /*
  1101.      * Count the number of lines in the file.  If under the max display
  1102.      * size, use that instead.
  1103.      */
  1104.     num_lines = 0;
  1105.     while (fgets(line, LLEN, fp)) {
  1106.     num_lines++;
  1107.     if (num_lines >= DISPLAY_FILE_SIZE) break;
  1108.     }
  1109.  
  1110.     (void) fclose(fp);
  1111.  
  1112.     /* Ignore empty files */
  1113.     if (num_lines == 0) return;
  1114.  
  1115.     num_args = 0;
  1116.     XtSetArg(args[num_args], XtNtitle, str);    num_args++;
  1117.  
  1118.     popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass,
  1119.                            toplevel, args, num_args);
  1120.  
  1121.     num_args = 0;
  1122.     XtSetArg(args[num_args], XtNscrollHorizontal,
  1123.                 XawtextScrollWhenNeeded);    num_args++;
  1124.     XtSetArg(args[num_args], XtNscrollVertical,
  1125.                 XawtextScrollWhenNeeded);    num_args++;
  1126.     XtSetArg(args[num_args], XtNtype, XawAsciiFile);        num_args++;
  1127.     XtSetArg(args[num_args], XtNstring, str);            num_args++;
  1128.     XtSetArg(args[num_args], XtNdisplayCaret, False);        num_args++;
  1129.     XtSetArg(args[num_args], XtNtranslations,
  1130.     XtParseTranslationTable(display_translations));        num_args++;
  1131.  
  1132.     dispfile = XtCreateManagedWidget(
  1133.             "text",            /* name */
  1134.             asciiTextWidgetClass,
  1135.             popup,            /* parent widget */
  1136.             args,            /* set some values */
  1137.             num_args);        /* number of values to set */
  1138.  
  1139.     /* Get font and border information. */
  1140.     num_args = 0;
  1141.     XtSetArg(args[num_args], XtNfont,          &fs);           num_args++;
  1142.     XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
  1143.     XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
  1144.     XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
  1145.     XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
  1146.     XtGetValues(dispfile, args, num_args);
  1147.  
  1148.     /*
  1149.      * Font height is ascent + descent.
  1150.      *
  1151.      * The data files are currently set up assuming an 80 char wide window
  1152.      * and a fixed width font.  Soo..
  1153.      */
  1154.     new_height = num_lines * (fs->ascent + fs->descent) +
  1155.                         top_margin + bottom_margin;
  1156.     new_width  = 80 * fs->max_bounds.width + left_margin + right_margin;
  1157.  
  1158.     /* Set the new width and height. */
  1159.     num_args = 0;
  1160.     XtSetArg(args[num_args], XtNwidth,  new_width);  num_args++;
  1161.     XtSetArg(args[num_args], XtNheight, new_height); num_args++;
  1162.     XtSetValues(dispfile, args, num_args);
  1163.  
  1164.     nh_XtPopup(popup, XtGrabNone, None);
  1165. }
  1166.  
  1167.  
  1168. /* yn_function ------------------------------------------------------------- */
  1169. /* (not threaded) */
  1170.  
  1171. static const char *yn_quitchars = " \n\r";
  1172. static const char *yn_choices;    /* string of acceptable input */
  1173. static char yn_def;
  1174. static char yn_return;        /* return value */
  1175. static char yn_esc_map;        /* ESC maps to this char. */
  1176. static Widget yn_popup;        /* popup for the yn fuction (created once) */
  1177. static Widget yn_label;        /* label for yn function (created once) */
  1178. static boolean yn_getting_num;    /* TRUE if accepting digits */
  1179. static int yn_ndigits;        /* digit count */
  1180. static long yn_val;        /* accumulated value */
  1181.  
  1182. static const char yn_translations[] =
  1183.     "#override\n\
  1184.      <Key>: yn_key()";
  1185.  
  1186. /*
  1187.  * Convert the given key event into a character.  If the key maps to
  1188.  * more than one character only the first is returned.  If there is
  1189.  * no conversion (i.e. just the CTRL key hit) a NULL is returned.
  1190.  */
  1191. char
  1192. key_event_to_char(key)
  1193.     XKeyEvent *key;
  1194. {
  1195.     char keystring[MAX_KEY_STRING];
  1196.     int nbytes;
  1197.  
  1198.     nbytes = XLookupString(key, keystring, MAX_KEY_STRING, NULL, NULL);
  1199.  
  1200.     /* Modifier keys return a zero lengh string when pressed. */
  1201.     if (nbytes == 0) return '\0';
  1202.  
  1203.     return keystring[0];
  1204. }
  1205.  
  1206. /*
  1207.  * Called when we get a key press event on a yn window.
  1208.  */
  1209. /* ARGSUSED */
  1210. static void
  1211. yn_key(w, event, params, num_params)
  1212.     Widget w;
  1213.     XEvent *event;
  1214.     String *params;
  1215.     Cardinal *num_params;
  1216. {
  1217.     char ch;
  1218.  
  1219.     if(appResources.slow && !input_func)
  1220.     extern_map_input(event);
  1221.  
  1222.     ch = key_event_to_char((XKeyEvent *) event);
  1223.  
  1224.     if (ch == '\0') {    /* don't accept nul char or modifier event */
  1225.     /* no bell */
  1226.     return;
  1227.     }
  1228.  
  1229.     if (!yn_choices) {            /* accept any input */
  1230.     yn_return = ch;
  1231.     } else {
  1232.     ch = lowc(ch);            /* move to lower case */
  1233.  
  1234.     if (ch == '\033') {
  1235.         yn_getting_num = FALSE;
  1236.         yn_return = yn_esc_map;
  1237.     } else if (index(yn_quitchars, ch)) {
  1238.         yn_return = yn_def;
  1239.     } else if (index(yn_choices, ch)) {
  1240.         if (ch == '#') {
  1241.         if (yn_getting_num) {    /* don't select again */
  1242.             X11_nhbell();
  1243.             return;
  1244.         }
  1245.         yn_getting_num = TRUE;
  1246.         yn_ndigits = 0;
  1247.         yn_val = 0;
  1248.         return;            /* wait for more input */
  1249.         }
  1250.         yn_return = ch;
  1251.         if (ch != 'y') yn_getting_num = FALSE;
  1252.     } else {
  1253.         if (yn_getting_num) {
  1254.         if (digit(ch)) {
  1255.             yn_ndigits++;
  1256.             yn_val = (yn_val * 10) + (long) (ch - '0');
  1257.             return;            /* wait for more input */
  1258.         }
  1259.         if (yn_ndigits && (ch == '\b' || ch == 127/*DEL*/)) {
  1260.             yn_ndigits--;
  1261.             yn_val = yn_val/ 10;
  1262.             return;            /* wait for more input */
  1263.         }
  1264.         }
  1265.         X11_nhbell();        /* no match */
  1266.         return;
  1267.     }
  1268.  
  1269.     if (yn_getting_num) {
  1270.         yn_return = '#';
  1271.         yn_number = yn_val;    /* assign global */
  1272.     }
  1273.     }
  1274.     exit_x_event = TRUE;    /* exit our event handler */
  1275. }
  1276.  
  1277.  
  1278. char
  1279. X11_yn_function(ques, choices, def)
  1280.     const char *ques;
  1281.     const char *choices;
  1282.     char def;
  1283. {
  1284.     static Boolean need_to_init = True;
  1285.     char buf[QBUFSZ];
  1286.     Arg args[4];
  1287.     Cardinal num_args;
  1288.  
  1289.     yn_choices = choices;    /* set up globals for callback to use */
  1290.     yn_def     = def;
  1291.  
  1292.     /*
  1293.      * This is sort of a kludge.  There are quite a few places in the main
  1294.      * nethack code where a pline containing information is followed by a
  1295.      * call to yn_function().  There is no flush of the message window
  1296.      * (it is implicit in the tty window port), so the line never shows
  1297.      * up for us!  Solution: do our own flush.
  1298.      */
  1299.     if (WIN_MESSAGE != WIN_ERR)
  1300.     display_message_window(&window_list[WIN_MESSAGE]);
  1301.  
  1302.     if (choices) {
  1303.     /* ques [choices] (def) */
  1304.     if ((1 + strlen(ques) + 2 + strlen(choices) + 4) >= QBUFSZ)
  1305.         panic("yn_function:  question too long");
  1306.     if (def)
  1307.         Sprintf(buf, "%s [%s] (%c)", ques, choices, def);
  1308.     else
  1309.         Sprintf(buf, "%s [%s] ", ques, choices);
  1310.  
  1311.     /* escape maps to 'q' or 'n' or default, in that order */
  1312.     yn_esc_map = (index(choices, 'q') ? 'q' :
  1313.              (index(choices, 'n') ? 'n' :
  1314.                         def));
  1315.     } else {
  1316.     if ((1 + strlen(ques)) >= QBUFSZ)
  1317.         panic("yn_function:  question too long");
  1318.     Strcpy(buf, ques);
  1319.     }
  1320.  
  1321.     if (!appResources.slow && need_to_init) {
  1322.     need_to_init = False;
  1323.  
  1324.     XtSetArg(args[0], XtNallowShellResize, True);
  1325.     yn_popup = XtCreatePopupShell("query", transientShellWidgetClass,
  1326.                     toplevel, args, ONE);
  1327.  
  1328.     num_args = 0;
  1329.     XtSetArg(args[num_args], XtNtranslations,
  1330.         XtParseTranslationTable(yn_translations));    num_args++;
  1331.     yn_label = XtCreateManagedWidget("yn_label",
  1332.                 labelWidgetClass,
  1333.                 yn_popup,
  1334.                 args, num_args);
  1335.  
  1336.     XtRealizeWidget(yn_popup);
  1337.     }
  1338.  
  1339.     if(appResources.slow)
  1340.     input_func = yn_key;
  1341.  
  1342.     num_args = 0;
  1343.     XtSetArg(args[num_args], XtNlabel, buf);    num_args++;
  1344.     XtSetValues(yn_label, args, num_args);
  1345.  
  1346.     if(!appResources.slow) {
  1347.     /*
  1348.      * Due to some kind of weird bug in the X11R4 and X11R5 shell, we
  1349.      * need to set the label twice to get the size to change.
  1350.      */
  1351.     num_args = 0;
  1352.     XtSetArg(args[num_args], XtNlabel, buf); num_args++;
  1353.     XtSetValues(yn_label, args, num_args);
  1354.  
  1355.     positionpopup(yn_popup);
  1356.     nh_XtPopup(yn_popup, XtGrabExclusive, yn_label);
  1357.     }
  1358.  
  1359.     yn_getting_num = FALSE;
  1360.     (void) x_event(EXIT_ON_EXIT);
  1361.  
  1362.     if(appResources.slow) {
  1363.     input_func = 0;
  1364.     num_args = 0;
  1365.     XtSetArg(args[num_args], XtNlabel, " ");    num_args++;
  1366.     XtSetValues(yn_label, args, num_args);
  1367.     } else {
  1368.     nh_XtPopdown(yn_popup);    /* this removes the event grab */
  1369.     }
  1370.  
  1371.     return yn_return;
  1372. }
  1373.  
  1374. /* End global functions ==================================================== */
  1375.  
  1376. /*
  1377.  * Before we wait for input via nhgetch() and nh_poskey(), we need to
  1378.  * do some pre-processing.
  1379.  */
  1380. static int
  1381. input_event(exit_condition)
  1382.     int exit_condition;
  1383. {
  1384.     if (WIN_STATUS != WIN_ERR)    /* hilighting on the fancy status window */
  1385.     check_turn_events();
  1386.     if (WIN_MAP != WIN_ERR)    /* make sure cursor is not clipped */
  1387.     check_cursor_visibility(&window_list[WIN_MAP]);
  1388.     if (WIN_MESSAGE != WIN_ERR)    /* reset pause line */
  1389.     set_last_pause(&window_list[WIN_MESSAGE]);
  1390.  
  1391.     return x_event(exit_condition);
  1392. }
  1393.  
  1394.  
  1395. /*ARGSUSED*/
  1396. void
  1397. msgkey(w, data, event)
  1398.     Widget w;
  1399.     XtPointer data;
  1400.     XEvent *event;
  1401. {
  1402.     extern_map_input(event);
  1403. }
  1404.  
  1405. /*
  1406.  * Set up the playing console.  This has three major parts:  the
  1407.  * message window, the map, and the status window.
  1408.  */
  1409. static void
  1410. init_standard_windows()
  1411. {
  1412.     Widget form, message_viewport, map_viewport, status;
  1413.     Arg args[8];
  1414.     Cardinal num_args;
  1415.     Dimension message_vp_width, map_vp_width, status_width, max_width;
  1416.     int map_vp_hd, status_hd;
  1417.     struct xwindow *wp;
  1418.  
  1419.  
  1420.     num_args = 0;
  1421.     XtSetArg(args[num_args], XtNallowShellResize, True);    num_args++;
  1422.     form = XtCreateManagedWidget("nethack",
  1423.                 formWidgetClass,
  1424.                 toplevel, args, num_args);
  1425.  
  1426.     XtAddEventHandler(form, KeyPressMask, False,
  1427.               (XtEventHandler) msgkey, (XtPointer) 0);
  1428.  
  1429.     /*
  1430.      * Create message window.
  1431.      */
  1432.     WIN_MESSAGE = message_win = find_free_window();
  1433.     wp = &window_list[message_win];
  1434.     wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
  1435.     wp->popup = (Widget) 0;
  1436.     create_message_window(wp, FALSE, form);
  1437.     message_viewport = XtParent(wp->w);
  1438.  
  1439.  
  1440.     /* Tell the form that contains it that resizes are OK. */
  1441.     num_args = 0;
  1442.     XtSetArg(args[num_args], XtNresizable, True);        num_args++;
  1443.     XtSetArg(args[num_args], XtNleft,       XtChainLeft);    num_args++;
  1444.     XtSetArg(args[num_args], XtNtop,       XtChainTop);        num_args++;
  1445.     XtSetValues(message_viewport, args, num_args);
  1446.  
  1447.     if(appResources.slow) {
  1448.     num_args = 0;
  1449.     XtSetArg(args[num_args], XtNtranslations,
  1450.          XtParseTranslationTable(yn_translations)); num_args++;
  1451.     yn_label = XtCreateManagedWidget("yn_label",
  1452.                      labelWidgetClass,
  1453.                      form,
  1454.                      args, num_args);
  1455.     num_args = 0;
  1456.     XtSetArg(args[num_args], XtNfromVert, message_viewport); num_args++;
  1457.     XtSetArg(args[num_args], XtNresizable, True);    num_args++;
  1458.     XtSetArg(args[num_args], XtNlabel, " ");    num_args++;
  1459.     XtSetValues(yn_label, args, num_args);
  1460.     }
  1461.  
  1462.     /*
  1463.      * Create the map window & viewport and chain the viewport beneath the
  1464.      * message_viewport.
  1465.      */
  1466.     map_win = find_free_window();
  1467.     wp = &window_list[map_win];
  1468.     wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
  1469.     wp->popup = (Widget) 0;
  1470.     create_map_window(wp, FALSE, form);
  1471.     map_viewport = XtParent(wp->w);
  1472.  
  1473.     /* Chain beneath message_viewport or yn window. */
  1474.     num_args = 0;
  1475.     if(appResources.slow) {
  1476.     XtSetArg(args[num_args], XtNfromVert, yn_label);    num_args++;
  1477.     } else {
  1478.     XtSetArg(args[num_args], XtNfromVert, message_viewport);num_args++;
  1479.     }
  1480.     XtSetArg(args[num_args], XtNbottom, XtChainBottom);        num_args++;
  1481.     XtSetValues(map_viewport, args, num_args);
  1482.  
  1483.     /* Create the status window, with the form as it's parent. */
  1484.     status_win = find_free_window();
  1485.     wp = &window_list[status_win];
  1486.     wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
  1487.     wp->popup = (Widget) 0;
  1488.     create_status_window(wp, FALSE, form);
  1489.     status = wp->w;
  1490.  
  1491.     /*
  1492.      * Chain the status window beneath the viewport.  Mark the left and right
  1493.      * edges so that they stay a fixed distance from the left edge of the
  1494.      * parent, as well as the top and bottom edges so that they stay a fixed
  1495.      * distance from the bottom of the parent.  We do this so that the status
  1496.      * will never expand or contract.
  1497.      */
  1498.     num_args = 0;
  1499.     XtSetArg(args[num_args], XtNfromVert, map_viewport);    num_args++;
  1500.     XtSetArg(args[num_args], XtNleft,      XtChainLeft);        num_args++;
  1501.     XtSetArg(args[num_args], XtNright,      XtChainLeft);        num_args++;
  1502.     XtSetArg(args[num_args], XtNtop,      XtChainBottom);    num_args++;
  1503.     XtSetArg(args[num_args], XtNbottom,      XtChainBottom);    num_args++;
  1504.     XtSetValues(status, args, num_args);
  1505.  
  1506.  
  1507.     /*
  1508.      * Realize the popup so that the status widget knows it's size.
  1509.      *
  1510.      * If we unset MappedWhenManaged then the DECwindow driver doesn't
  1511.      * attach the nethack toplevel to the highest virtual root window.
  1512.      * So don't do it.
  1513.      */
  1514.     /* XtSetMappedWhenManaged(toplevel, False); */
  1515.     XtRealizeWidget(toplevel);
  1516.     /*
  1517.      * The message window was the size we want the viewport to take (when
  1518.      * realized).  Now change to our real height.  Do this before we resize
  1519.      * so that the vertical scrollbar is activated and is taken into account
  1520.      * when calculating the widget size.  If we do this last, then the
  1521.      * message window ends up being short by one scrollbar width.  [Brain-dead
  1522.      * viewport widget.]
  1523.      */
  1524.     set_message_height(&window_list[message_win], (int) flags.msg_history);
  1525.  
  1526.     /*
  1527.      * Now get the default widths of the windows.
  1528.      */
  1529.     XtSetArg(args[0], XtNwidth, &message_vp_width);
  1530.     XtGetValues(message_viewport, args, ONE);
  1531.     XtSetArg(args[0], XtNwidth, &map_vp_width);
  1532.     XtSetArg(args[1], XtNhorizDistance, &map_vp_hd);
  1533.     XtGetValues(map_viewport, args, TWO);
  1534.     XtSetArg(args[0], XtNwidth, &status_width);
  1535.     XtSetArg(args[1], XtNhorizDistance, &status_hd);
  1536.     XtGetValues(status, args, TWO);
  1537.  
  1538.     /*
  1539.      * Adjust positions and sizes.  The message viewport widens out to the
  1540.      * widest width.  Both the map and status are centered by adjusting
  1541.      * their horizDistance.
  1542.      */
  1543.     if (map_vp_width < status_width || map_vp_width < message_vp_width) {
  1544.     if (status_width > message_vp_width) {
  1545.         XtSetArg(args[0], XtNwidth, status_width);
  1546.         XtSetValues(message_viewport, args, ONE);
  1547.         max_width = status_width;
  1548.     } else {
  1549. /***** The status display looks better when left justified.
  1550.         XtSetArg(args[0], XtNhorizDistance,
  1551.                 status_hd+((message_vp_width-status_width)/2));
  1552.         XtSetValues(status, args, ONE);
  1553. *****/
  1554.         max_width = message_vp_width;
  1555.     }
  1556.     XtSetArg(args[0], XtNhorizDistance, map_vp_hd+((int)(max_width-map_vp_width)/2));
  1557.     XtSetValues(map_viewport, args, ONE);
  1558.  
  1559.     } else {    /* map is widest */
  1560.     XtSetArg(args[0], XtNwidth, map_vp_width);
  1561.     XtSetValues(message_viewport, args, ONE);
  1562.  
  1563. /***** The status display looks better when left justified.
  1564.     XtSetArg(args[0], XtNhorizDistance,
  1565.                 status_hd+((map_vp_width-status_width)/2));
  1566.  
  1567.     XtSetValues(status, args, ONE);
  1568. *****/
  1569.     }
  1570.     /*
  1571.      * Clear all data values on the fancy status widget so that the values
  1572.      * used for spacing don't appear.  This needs to be called some time
  1573.      * after the fancy status widget is realized (above, with the game popup),
  1574.      * but before it is popped up.
  1575.      */
  1576.     null_out_status();
  1577.     /*
  1578.      * Set the map size to its standard size.  As with the message window
  1579.      * above, the map window needs to be set to its constrained size until
  1580.      * its parent (the viewport widget) was realized.
  1581.      *
  1582.      * Move the message window's slider to the bottom.
  1583.      */
  1584.     set_map_size(&window_list[map_win], COLNO, ROWNO);
  1585.     set_message_slider(&window_list[message_win]);
  1586.  
  1587.     /* grab initial input focus */
  1588.     if (appResources.autofocus) {
  1589.     Display *dpy = XtDisplay(toplevel);
  1590.     Window   win = XtWindow(toplevel), current;
  1591.     int      revert;
  1592.  
  1593.     /*
  1594.      * We don't actually care about the `revert' value; this mainly serves
  1595.      * the purpose of synchronizing with the popup.
  1596.      */
  1597.     XGetInputFocus(dpy, ¤t, &revert);
  1598.  
  1599.     /* attach the keyboard to the main window */
  1600.     if (win != current) {
  1601.         sleep(1);    /* ugh, delay so window is showing.. */
  1602.         XSetInputFocus(dpy, win, revert, CurrentTime);
  1603.     }
  1604.     }
  1605.  
  1606.     /* attempt to catch fatal X11 errors before the program quits */
  1607.     (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup);
  1608.  
  1609.     /* We can now print to the message window. */
  1610.     flags.window_inited = 1;
  1611. }
  1612.  
  1613.  
  1614. void
  1615. nh_XtPopup(w, g, childwid)
  1616.     Widget w;        /* widget */
  1617.     int    g;        /* type of grab */
  1618.     Widget childwid;    /* child to recieve focus (can be None) */
  1619. {
  1620.     XtPopup(w, (XtGrabKind)g);
  1621.     if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid);
  1622. }
  1623.  
  1624. void
  1625. nh_XtPopdown(w)
  1626.     Widget w;
  1627. {
  1628.     XtPopdown(w);
  1629.     if (appResources.autofocus) XtSetKeyboardFocus(toplevel, None);
  1630. }
  1631.  
  1632. void
  1633. win_X11_init()
  1634. {
  1635. #ifdef OPENWINBUG
  1636.     /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these
  1637.      * two routines will not be found when linking.  An apparently correct
  1638.      * executable is produced, along with nasty messages and a failure code
  1639.      * returned to make.  The routines are in the static libXmu.a and
  1640.      * libXmu.sa.4.0, but not in libXmu.so.4.0.  Rather than fiddle with
  1641.      * static linking, we do this.
  1642.      */
  1643.     if (rn2(2) > 2) {
  1644.     /* i.e., FALSE that an optimizer probably can't find */
  1645.     get_wmShellWidgetClass();
  1646.     get_applicationShellWidgetClass();
  1647.     }
  1648. #endif
  1649.     return;
  1650. }
  1651.  
  1652. /*winX.c*/
  1653.